package de.jmda.mproc.swingui;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Modifier;

import javax.annotation.processing.AbstractProcessor;

import org.apache.commons.lang.ClassUtils;

import de.jmda.util.RuntimeUtil;
import de.jmda.util.classpath.StringFilter;


/**
 * Filter for <code>File</code> objects and .jar file resources.
 */
public class LaunchableAnnotationProcessorFilter
		implements FileFilter, StringFilter
{
//	private final static Logger LOGGER =
//			Logger.getLogger(LaunchableAnnotationProcessorFilter.class);

	/**
	 * Accepts files that are no directories and that are accepted by {@link
	 * #accept(String)}.
	 *
	 * @see java.io.FileFilter#accept(java.io.File)
	 */
	@Override
  public boolean accept(File file)
  {			
		if (file.isDirectory())
		{
			// reject directories, they can not be launchable annotation processors
			return false;
		}

		return accept(file.getPath());
  }

	/**
	 * @param filename
	 * @return <code>true</code> if <code>filename</code> represents a
	 *         <ul>
	 *           <li>loadable class and
	 *           <li>non abstract class and
	 *           <li>non private class and
	 *           <li>subclass of {@link AbstractProcessor},
	 *         </ul>
	 *         <code>false</code> otherwise
	 */
	@Override
  public boolean accept(String filename)
  {
		if (filename.endsWith(".class") == false)
		{
			// reject non .class files, they can not be annotation processors
			return false;
		}
		
		String clazzname =
				filename.substring(0, filename.lastIndexOf('.'))
				        .replace(RuntimeUtil.FILE_SEPARATOR, ".")
				        .replace("/", ".");

		Class<?> clazz = null;

		try
    {
      clazz = Class.forName(clazzname);
    }
//    catch (ClassNotFoundException e)
//    {
//    	LOGGER.warn(
//    			"failure getting class for name " + clazzname, e);
//    	return false;
//    }
//    catch (UnsatisfiedLinkError e)
//    {
//    	LOGGER.warn(
//    			"failure getting class for name " + clazzname, e);
//    	return false;
//    }
//    catch (NoClassDefFoundError e)
//    {
//    	LOGGER.warn(
//    			"failure getting class for name " + clazzname, e);
//    	return false;
//    }
		catch (Throwable e)
		{
			// ignore any problems with loading arbitrary classes, just return false
//    	LOGGER.warn(
//    			"failure getting class for name " + clazzname, e);
			return false;
		}
		
    if (Modifier.isAbstract(clazz.getModifiers()))
    {
    	return false;
    }
    
    if (Modifier.isPrivate(clazz.getModifiers()))
    {
    	return false;
    }
    
		return ClassUtils.isAssignable(clazz, AbstractProcessor.class);
  }
}